1990-Club80-07 Nr.31 S.17-22
Harddisk-Einbindung ins CP/M3-BIOShier am Beispiel des OMTI 5527 RLL Controllers und einer Platte mit 615 Zylindern und 4 Köpfen (32 MB im RLL Format)Helmut Bernhardt, Peter Petersen Die HardwareDer Aufwand in Hardware, um einen PC-Harddisk-Controller wie die verschiedenen OMTI-Typen an den ECB-Bus oder auch an andere Z80-Bus-Systeme anzuschließen, ist minimal. Beim ECB-Bus bestehen die Probleme hauptsächlich in der ungeeigneten Geometrie des Controllers, der die Breite der Europakarten von 10 cm überschreitet. Die Montage auf eine ECB-Bus Trägerkarte, die auch die beiden zur Busanpassung nötigen ICs aufnimmt, muß für jedes Gerät individuell gelöst werden. Die Busanpassung beschränkt sich auf die Umverlegung der ECB-Adressen an die Slotadressen des Controllers, damit bei einem Zugriff der CPU unter einer für den Controller vorgesehenen Portadresse am Controller die Portadresse 320H(-323H), unter der der Controller im PC decodiert ist, anliegt. Außerdem müssen aus den ECB-Signalen /RD, /WR, und /IORQ die PC-Bus-Signale /IOR und /IOW mit zwei OR-Gattern eines 74LS32 erzeugt werden. Auch das low aktive /RESET des ECB-Bus muß über einen 74LS04-Inverter in das high aktive RESET des PC-Bus umgesetzt werden. Da 4 aufeinanderfolgende Portadressen benötigt werden, müssen A0 und A1 direkt an den Controller gelangen. Für eine Adreßlage bei D0H-D3H am ECB-Bus ist am Ende dieses Artikels eine Beschaltung gezeigt, die folgende Pegel-Übersetzung bewirkt: Adresse : A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 --------------------------------------------------------- ECB Port D0H : = = 1 1 0 1 0 0 x x PC Port 320H : 1 1 0 0 1 0 0 0 x x Außerdem ist an AEN und A10-A19 des Controllers GND und an /DACK3 und /MEMR +5V zu legen. Außer dem OMTI 5510 benötigen alle OMTI-Controller am Slot-Pin B9 +12V Versorgungsspannung. Selbstverständlich müssen die Daten D0-D7 an die gleichen Eingänge des Controllers gelegt werden. Die SoftwareWesentlich anspruchsvoller ist die Software-Einbindung der Festplatte in das BIOS des CP/M plus. Mit den unter CP/M bestehenden Möglichkeiten zur Verwaltung der Files auf einer Platte (Unterteilung in User 0 bis User 15) lassen sich nur begrenzte Mengen an Files übersichtlich handhaben. Deshalb ist es bei größeren Platten sinnvoll, diese in mehrere logische Laufwerke zu partitionieren. Noch handhabbar sind dabei Größen von einigen Megabyte Kapazität. Danach könnte eine 32MB-Platte in 4 Partitionen aufgeteilt werden. Die sich anbietende Aufteilung, daß alle Spuren unter einem Kopf als ein Laufwerk behandelt werden, bedeutet, daß nach je 26 Sektoren der Kopf eine Spur weiter bewegt werden muß. Der Spurwechsel ist bei Festplattenzugriffen aber die zeitraubendste Aktion und sollte so wenig wie möglich vorkommen. Deshalb wurde die Partitionierung hier auch anders durchgeführt: Eine logische Spur umfaßt alle 4 Spuren (Köpfe) eines Zylinders. Es werden nacheinander erst die 4 Spuren unter allen 4 Köpfen gelesen/geschrieben, bevor der Kopfschlitten um eine Position weiterbewegt wird. Dadurch können nacheinander 104 Sektoren verholt werden, ohne zwischendurch steppen zu müssen. Einer Partition wird dabei ein zusammenhängender Bereich von Zylindern zugeordnet: die Nummer des letzten absoluten Zylinders einer Partition ist die Anzahl Spuren und die Nummer des letzten absoluten Zylinders der vorherigen Partition ist die Anzahl reservierter Systemspuren. Spur-Nr. 0 1 154 307 460 615 Partit. 0 =############--------------------------------------- Partit. 1 =============#############-------------------------- Partit. 2 ==========================#############------------- Partit. 3 =======================================############# ===== reservierte Systemspuren ##### Datenspuren der Partition Das BDOS kennt für Disk-I/O nur die Adressen einer Tabelle mit dem Namen @dtbl (drive table). In dieser Tabelle stehen die Adressen von 16 Disk-Parameter-Headern (DPHs) für 16 Laufwerke in der Reihenfolge ihrer logischen Namen (A, B, ...P). Nicht existierende Laufwerke erhalten hier den Eintrag 0. Wenn in einem Sourcecode-Modul nur die Drive Table und die DPHs und DPBs für RAM-Floppy und Harddisk enthalten sind, könnte das so aussehen: public @dtbl ; Drive Table public fdsd0,fdsd1,fdsd2,fdsd3 ; dph's fuer 4 Floppies public fdram ; dph RAM-Floppy public hdsk0,hdsk1,hdsk2,hdsk3 ; dph's fuer Harddisk 0-3 extrn hdlogi,hdinit,hd1init ; Harddisk Routinen extrn hdwrit,hdread maclib xcpm3 ; mit hdpb-Macro für große Drives cseg ; Drivetable und dpb's im Common ; Drive Table (zeigt auf die DPB's der verfuegbaren Laufwerke) @dtbl dw fdsd0,fdsd1,fdsd2,fdsd3 ; Floppy Drives dw fdram ; RAM-Floppy dw hdsk0,hdsk1,hdsk2,hdsk3 ; Harddisks dw 0,0,0,0,0,0,0 ; nicht benutzt ;Die Einträge in @dtbl weisen auf Adressen der DPHs, wobei die Lables ;nicht am Anfang der xDPHs stehen. Der Aufbau der xDPHs sieht so aus: desg ; die DPHs koennen im gebankten RAM stehen ; extended disk parameter header (xDPH) der Harddisk-Partitionen drva: dw hdwrit ; Routinen zum Schreiben dw hdread ; und Lesen eines Sektors dw hdlogi ; Einloggen des Drives dw hdinit ; Initialisieren des HDC dw 0 ; relatives drive 0 dw 0 ; media flag : not used hdsk0 dph 0,hddpb0 ; Skew-Tabelle und xDPB drvb: dw hdwrit,hdread,hdlogi dw hdinit ; kann auf RET zeigen db 1 ; relative drive 1 db 0 ; media flag : not used hdsk2 dpb 0,hddpb1 ;------------------------------- drvd: dw hdwrit,hdread,hdlogi dw hd1init ; kann auf RET zeigen db 3 ; relative drive 3 db 0 ; media flag : not used hdsk3 dph 0,hddpb3 'dph' ist ein Macro-Aufruf, der in CPM3.LIB aufgelöst wird. Am Anfang
des Moduls, in dem das xDPH steht, ist
Da der Skew der Festplatten bereits beim Formatieren durch physika- lischen Versatz der Sektoren auf der Spur vorgegeben wird, ist ein Soft-Skew nicht nötig: anstelle der Adresse einer Skew-Tabelle kann als erster Parameter für dph '0' angegeben werden. Die Einträge hddpb0 bis hddpb3 geben die Adressen der xDPB's der vier Harddisk-Partitionen an. Diese können wieder mit einem Macro erzeugt werden: cseg ; die DPHs müssen im Common liegen ; hard disk parameter block macros hddpb0 hdpb 512,104,154,4096,2048,1,8000h ; partition 0 hddpb1 hdpb 512,104,307,4096,2048,154,8000h ; partition 1 hddpb2 hdpb 512,104,460,4096,2048,307,8000h ; partition 2 hddpb3 hdpb 512,104,615,4096,2048,460,8000h ; partition 3 ; | | | | | | | ; | | | | | | +----flag für nonre- ; | | | | | | movable media ; | | | | | +----reserv. Systemspuren ; | | | | +----max. Anzahl DIR-Einträge ; | | | +----Blockgröße (die durch einen ; | | | DIR-Eintrag verwaltet wird) ; | | +----Anzahl Zylinder des Laufwerks ; | +----Sektoren pro Zylinder (4 tracks mit 26 secs) +----Bytes pro Sektor Aufgrund des optionalen Eintrags 8000h wird das Laufwerk vom BDOS als 'nonremovable media' angesehen, woraufhin nicht bei jedem Zugriff ein neues Einloggen durchgeführt wird. 'hdpb' ist (ähnlich dem dpb in CPM3.LIB) ein in XCPM3.LIB zusätzlich vorhandener Macro, der auch für Laufwerke mit einer Kapazität von mehr als 8 MB einen richtigen Disk Parameter Block erzeugt. Das Source-Modul (angenommen, es heißt MOVE.ASM) das diese Datenstrukturen enthält, wird mit 'rmac move $pz sz' assembliert (in einem SUBMIT-File sind 2 $-Zeichen einzutragen). M80 kann die Macrobibliotheken CPM3 und XCPM3 nicht benutzen. Da für die Datenstrukturen aber keinerlei Maschinenbefehle nötig sind, braucht man sich auch nicht unbedingt mit den von RMAC einzig verstandenen 8080-Mnemonics herumschlagen. Die eigentlichen Disk-I/O-Routinen können in einem anderen Modul formuliert werden, wobei man sich die Fähigkeit von M80 zunutzemachen kann, Z80 Mnemonics zu verstehen. Im Kopf des Moduls mit diesen Datenstrukturen sind sämtliche Lables wie @dtbl auf die aus anderen Modulen zugegriffen wird mit 'public' bekanntzugeben, und alle Einträge in diesen Tabellen, die nicht in diesem Modul selbst als Lable auftauchen, mit 'extrn' als außerhalb stehend zu benennen. Bei ausreichend bereigestelltem RAM-Speicher legt GENCPM Direktory Buffer in Bank 0 (Systembank) und Data-Buffer in anderen dafür angegebenen Banks an (siehe unten). Die Routinen 'hdwrit' und 'hdread' müssen also den Datentransfer zwischen Controller und verschiedenen Banks unterstüzen. Beim Aufruf bekommen sie in den in BIOSKRNL zugewiesenen Variablen entsprechende Parameter übergeben. @dbnk ( 8Bit) Source-/Ziel-Bank für Holen/Ablegen eines Sektors beim Schreiben/Lesen @dma (16Bit) RAM-Adressen in der Bank, von wo ab mit aufsteigender Adresse die Daten des Sektors zu holen/abzulegen sind @adrv ( 8Bit) absolute Laufwerks-Nummer (entsprechend Position in qdtbl) @rdrv ( 8Bit) relative Laufwerks-Nummer (Zählung der Laufwerke für einen Controller) @trk (16Bit) Spur des Laufwerks @sect (16Bit) Sektor der Spur Diese Daten stehen alle in der Systembank 0 und müssen ausgewertet werden, bevor die in @dbnk vorgegebene Bank eingestellt wird und diese Daten dann nicht mehr zur Verfügung stehen. Die Übertragung von Daten erfogt direkt vom/zum Controller zur/von der Buffer-Bank. Da diese Bank dann eingeschaltet sein muß, kann die Übertragung nur von dieser Routine im Common durchgeführt werden. Das hat den Vorteil, daß der Common-Bereich keinen 512Byte-Zwischenspeicher enthalten muß, was auf Kosten der TPA geht, und daß nur ein Datentransfer nötig ist, was Geschwindigkeit bringt. Befehle an den OMTI-Controller bestehen aus einer Folge von 6 Bytes, die nacheinander an die relative Portadresse 0 des Controllers zu übertragen sind. Das erste Byte ist das eigentliche Befehlsbyte und die folgenden 5 Bytes sind Parameter des Befehls. Diese Bytefolge wird zunächst im RAM erzeugt und dann an den Controller ausgegeben. Das Parameterfeld im RAM sieht so aus: cfield: ; Befehlsparameter-Feld für HDC head: db 0 ; D7 = Bit 10 der Zylinder-Nummer ; D6 = 0. D5 = Nummer des zu bedienenden Lauf- ; werks (0 oder 1; an dem OMTI lassen sich ; 2 Festplatten anschließen) nicht mit der ; Partition eines Laufwerks verwechsel! ; D4-D0 : Head-Nummer sect: db 0 ; D6,D7 : Bit 9 und 8 der Zylinder-Nummer ; D5-D0 : Sector-Nummer cylind: db 0 ; D7-D0 : Bit 7 - 0 der Zylinder-Nummer bcount: db 1 ; Interleave-Count beim Formatieren ; Blockcount bei MultIO termin: db 2 ; D7-D5 : Command-Controll-Byte ; D4-D0 : nicht benutzt Für die Beschreibung der 'termin'-Bytes sei auf das Handbuch der OMTI-Controller verwiesen (das wollen wir uns hier sparen). Vor der Übertragung dieser Parameter ist der eigentliche Befehl direkt an den Controller auszugeben. Der Inhalt dieses Feldes wird in der Routine hdrw_common berechnet und in die Tabelle eingetragen 'hdscmd' übergibt die Bytes an den Controller. Die zwingend im Common anzusiedelnden Routinen 'hdrd' und 'hdwr' sowie der von beiden genutzte Ausgang 'termcmd1', der wieder die Bank 0 einschaltet, machen zusammen knapp 60 Bytes des kostbaren Common-Speichers aus, dem 512 Bytes eines Zwischenspeichers bei der anderen Variante gegenüberstehen. Bei einem Prof mit 9,2 MHz Systemtakt ist damit ein Interleave 1:1 möglich. Wegen insgesamt bereitgestellter Data-Buffer von 64K RAM erscheint ein erster Zugriff auf die Festplatte recht langsam, weil dann immer gleich riesige Datenmengen bewegt werden. Nachfolgende Zugriffe können dann aber aus dem Buffer leben und erreichen dann die Geschwindigkeit einer RAM-Floppy. Weiteres Tuneup am BIOSDa die Speicheraufteilung des Prof 180 recht ungünstig ist und dadurch bedingt auch die RAM-Floppy-Routinen umständlich mit '?xmove' über einen 128 Byte Zwischenspeicher im common arbeiten, wurde auch die ganze Speicherkonfiguration nach Conitec's Vorstellung aufgegeben und durch eine sinnvollere ersetzt. Speicherbereich Adreßlage nach Conitec neue Adreßlage ---------------------------------------------------------------------- Systembank 00000h-0efffh 00000h-0ffffh Common 0f000h-0ffffh 0f000h-0ffffh TPA 40000h-4efffh 10000h-1efffh CCP-Buffer 4f000h-4ffffh 1f000h-1ffffh weitere Banks ----------- 20000h-2ffffh RAM-Floppy 10000h-3ffffh 20000h-7ffffh + 50000h-7ffffh ---------------------------------------------------------------------- Die ursprüngliche Einteilung von Conitec ermöglicht den Einsatz von 4164-RAMs, wobei die Selektion der beiden 64K-Blöcke durch den Pegel von A18 erfolgt (was bei 41256-RAMs auch sinnvoll ist). Entsprechend liegen diese beiden Blöcke auf den physikalischen Adressen 0xxxxh und 4xxxxh. Da bei den heutigen RAM-Preisen der Einsatz von 4164-RAMs unwahrscheinlich ist und hier 41256-RAMs stecken, wurde auf die Möglichkeit des Abrüstens auf 128K verzichtet, so daß der Bereich, der für Banks und/oder RAM-Floppy zur Verfügung steht, zusammenhängt. Das vereinfacht die RAM-Floppy-Routinen gewaltig. Der Zugriff auf die RAM-Floppy erfolgt nur im DMA-Betrieb und zur Vereinfachung und Beschleunigung wurde die Sektorgröße von 128 auf 1024 Bytes erhöht und die Größe einer Spur auf 64K festgelegt. Die Track-Nr kann dann direkt (durch Addition des Offsets des RAM-Floppy-Anfanfs) in das Adreß-Zusatzbyte für den DMAC umgesetzt werden und aus der Sektor-Nummer kann durch Shiften um 2 Bits der Adreßanteil A15-A10 erhalten werden, A9-A0 sind immer 0 für die Anfangsadresse eines Sektors. Die RAM-Floppy-Routinen sind in RFLO.MAC versammelt. DPH und DPB der RAM-Floppy sowie die Routinen und Tabellen für Bankumschaltung und DMA sind neben den DPHs und DPBs für die Festplatte in MOVE.ASM enthalten. Durch die neue Speichereinteilung muß GENCPM bei der Erzeugung der Memory Segment Table auch mit anderen Parametern versorgt werden, als den in GENCPM.DAT bisher enthaltenen. Bei 64K Data-Buffer sind insgesamt 3 Segmente anzugeben (Common und TPA sowie CCP-Buffer werden hier nicht mitgezählt. Für jedes Segment sind dann je 3 Bytes anzugeben, die folgende Bedeutung haben. 1) high Byte der logischen Anfangsadresse der Bank 2) high Byte der Länge der Bank 3) Bank-NummerEine Angabe '00.80.02' bedeutet, daß die Bank 2 von 0000h bis 7fffh reicht (logische Adressen). Wo diese Bank physikalisch im Speicher liegt, spielt keine Rolle. Für die Bank 0 sind diese Angaben (speziel beim Prof 180) etwas
komplizierter. Der Prof 180 benutzt 4 KByte des Boot-ROMs (bzw. des auf
gleiche Adressen ins RAM kopierten ROM-Inhalts) vom BIOS des CP/M aus.
Deshalb muß für die Systembank als high Byte der Anfangsadresse 10 an-
gegeben werden, damit diese ROM-Routinen nicht überschrieben werden.
Als Länge ist die Differenz des von GENCPM vorher ausgegebenen Anfangs
des gebanten BDOS abzüglich dieser Adresse anzugeben. Die Bank-Nr ist
natürlich 00.
|